home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / ada / gnat-3.05- / gnat-3 / gnat-3.05-i486-linux-elf-bin / rts / 2dinterr.adb < prev    next >
Encoding:
Text File  |  1996-06-07  |  31.9 KB  |  955 lines

  1. ------------------------------------------------------------------------------
  2. --                                                                          --
  3. --                 GNU ADA RUNTIME LIBRARY (GNARL) COMPONENTS               --
  4. --                                                                          --
  5. --                     S Y S T E M . I N T E R R U P T S                    --
  6. --                                                                          --
  7. --                                  B o d y                                 --
  8. --                                                                          --
  9. --                             $Revision: 1.3 $                             --
  10. --                                                                          --
  11. --   Copyright (C) 1991,1992,1993,1994,1995,1996 Florida State University   --
  12. --                                                                          --
  13. -- GNARL is free software; you can  redistribute it  and/or modify it under --
  14. -- terms of the  GNU General Public License as published  by the Free Soft- --
  15. -- ware  Foundation;  either version 2,  or (at your option) any later ver- --
  16. -- sion. GNARL is distributed in the hope that it will be useful, but WITH- --
  17. -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
  18. -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
  19. -- for  more details.  You should have  received  a copy of the GNU General --
  20. -- Public License  distributed with GNARL; see file COPYING.  If not, write --
  21. -- to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, --
  22. -- MA 02111-1307, USA.                                                      --
  23. --                                                                          --
  24. -- As a special exception,  if other files  instantiate  generics from this --
  25. -- unit, or you link  this unit with other files  to produce an executable, --
  26. -- this  unit  does not  by itself cause  the resulting  executable  to  be --
  27. -- covered  by the  GNU  General  Public  License.  This exception does not --
  28. -- however invalidate  any other reasons why  the executable file  might be --
  29. -- covered by the  GNU Public License.                                      --
  30. --                                                                          --
  31. -- GNARL was developed by the GNARL team at Florida State University. It is --
  32. -- now maintained by Ada Core Technologies Inc. in cooperation with Florida --
  33. -- State University (http://www.gnat.com).                                  --
  34. --                                                                          --
  35. ------------------------------------------------------------------------------
  36.  
  37. --  This implemetation is targeted for 9X-Runtime build upon POSIX .4 thread
  38. --  extension standard using FSU Pthreads Library.
  39.  
  40. with Ada.Interrupts.Names; use Ada.Interrupts.Names;
  41. with Ada.Interrupts; use Ada.Interrupts;
  42.  
  43. with System.Storage_Elements;
  44. with Interfaces.C.POSIX_RTE;
  45. with Interfaces.C.POSIX_Error;
  46. with Interfaces.C.Pthreads;
  47. with System.Task_Primitives; use System.Task_Primitives;
  48. with System.Tasking; use System.Tasking;
  49. with System.Tasking.Rendezvous;
  50. with System.Tasking.Utilities;
  51. with System.Error_Reporting; use System.Error_Reporting;
  52. with Unchecked_Conversion;
  53.  
  54. package body System.Interrupts is
  55.  
  56.    package RTE renames Interfaces.c.POSIX_RTE;
  57.  
  58.    package POSIX_Error renames Interfaces.C.POSIX_Error;
  59.    use type POSIX_Error.Return_Code;
  60.  
  61.    package Utilities renames System.Tasking.Utilities;
  62.  
  63.    Failure : Interfaces.C.POSIX_Error.Return_Code
  64.       renames Interfaces.C.POSIX_Error.Failure;
  65.  
  66.    --  Locks and Cond variables for each Interrupt
  67.  
  68.    M : array (Ada.Interrupts.Interrupt_ID'Range) of Lock;
  69.  
  70.    C : array (Ada.Interrupts.Interrupt_ID'Range) of Condition_Variable;
  71.  
  72.    --  Interrupts to which a Handler or an Entry can be bound
  73.    Usable_Interrupts : array (Ada.Interrupts.Interrupt_ID'Range) of Boolean;
  74.  
  75.    type Handler_Assoc is record
  76.       H      : Ada.Interrupts.Parameterless_Handler;
  77.       Static : Boolean;   --  Indicates static binding;
  78.    end record;
  79.  
  80.    Null_Handler_Assoc : constant Handler_Assoc := Handler_Assoc'
  81.      (H => null, Static => false);
  82.  
  83.    --  Table to maintain current Interrupt Handler binding
  84.    User_Handlers :
  85.      array (Ada.Interrupts.Interrupt_ID'Range) of Handler_Assoc
  86.        := (others => Null_Handler_Assoc);
  87.  
  88.    type Entry_Assoc is record
  89.       T : Tasking.Task_ID;
  90.       E : Tasking.Task_Entry_Index;
  91.    end record;
  92.  
  93.    Null_Entry_Assoc : constant Entry_Assoc := Entry_Assoc'
  94.      (T => Tasking.Null_Task, E => Tasking.Null_Task_Entry);
  95.  
  96.    --  Table to maintain current Interrupt Entry binding
  97.    User_Entries : array (Ada.Interrupts.Interrupt_ID'Range) of Entry_Assoc
  98.      := (others => Null_Entry_Assoc);
  99.  
  100.    --  Table to maintain Task_ID of Handler_Task for each Interrupts.
  101.    Handler_Task_IDs :
  102.      array (Ada.Interrupts.Interrupt_ID'Range) of System.Tasking.Task_ID
  103.        := (others => System.Tasking.Null_Task);
  104.  
  105.    --  Table to maintain the information if a signal is blocked.
  106.    Status_Blocked :
  107.      array (Ada.Interrupts.Interrupt_ID'Range) of Boolean
  108.        := (others => false);
  109.  
  110.    --  Type and Head, Tail of the list containing Registered Interrupt
  111.    --  Handlers.
  112.  
  113.    type Registered_Handler;
  114.    type R_Link is access all Registered_Handler;
  115.  
  116.    type Registered_Handler is record
  117.       H :    Ada.Interrupts.Parameterless_Handler := null;
  118.       Next : R_Link := null;
  119.    end record;
  120.  
  121.    Registered_Handler_Head : R_Link := null;
  122.    Registered_Handler_Tail : R_Link := null;
  123.  
  124.  
  125.    task Handler_Manager is
  126.       entry Bind_Handler       (Interrupt : Ada.Interrupts.Interrupt_ID);
  127.       entry Unbind_Handler     (Interrupt : Ada.Interrupts.Interrupt_ID);
  128.       entry Block_Interrupt    (Interrupt : Ada.Interrupts.Interrupt_ID);
  129.       entry Unblock_Interrupt  (Interrupt : Ada.Interrupts.Interrupt_ID);
  130.       pragma Interrupt_Priority (System.Interrupt_Priority'Last);
  131.    end Handler_Manager;
  132.  
  133.    task type Handler_Task (Interrupt : Ada.Interrupts.Interrupt_ID) is
  134.       pragma Interrupt_Priority (System.Interrupt_Priority'First);
  135.    end Handler_Task;
  136.  
  137.    type Handler_Task_Access is access Handler_Task;
  138.  
  139.    Handler_Access :
  140.      array (Ada.Interrupts.Interrupt_ID'Range) of  Handler_Task_Access
  141.        := (others => null);
  142.  
  143.  
  144.    --  local procedures
  145.  
  146.    ---------------------------
  147.    -- Unmask_All_Interrupts --
  148.    ---------------------------
  149.  
  150.    procedure Unmask_All_Interrupts;
  151.  
  152.    ----------------------------
  153.    -- Thread_Block_Interrupt --
  154.    ----------------------------
  155.  
  156.    procedure Thread_Block_Interrupt (Interrupt : Ada.Interrupts.Interrupt_ID);
  157.  
  158.    ------------------------------
  159.    -- Thread_Unblock_Interrupt --
  160.    ------------------------------
  161.  
  162.    procedure Thread_Unblock_Interrupt
  163.      (Interrupt : Ada.Interrupts.Interrupt_ID);
  164.  
  165.    ----------------------------------
  166.    -- Initialize_Usable_Interrupts --
  167.    ----------------------------------
  168.  
  169.    procedure Initialize_Usable_Interrupts;
  170.  
  171.    --------------------
  172.    -- User_Installed --
  173.    --------------------
  174.  
  175.    --  return true if User_Handler or User_Entry is installed for the Interrupt
  176.    function User_Installed (Interrupt : Ada.Interrupts.Interrupt_ID)
  177.      return Boolean;
  178.  
  179.    -----------------
  180.    -- Signal_Task --
  181.    -----------------
  182.  
  183.    procedure Signal_Task
  184.      (T : System.Tasking.Task_ID; Interrupt : Ada.Interrupts.Interrupt_ID);
  185.  
  186.    ----------------------------------
  187.    -- Unprotected_Exchange_Handler --
  188.    ----------------------------------
  189.  
  190.    procedure Unprotected_Exchange_Handler
  191.      (Old_Handler : out Ada.Interrupts.Parameterless_Handler;
  192.       New_Handler : in Ada.Interrupts.Parameterless_Handler;
  193.       Interrupt   : in Ada.Interrupts.Interrupt_ID;
  194.       Static      : in boolean := false);
  195.  
  196.    -------------------
  197.    -- Is_Registered --
  198.    -------------------
  199.  
  200.    --  See if the Handler has been "pragma"ed using Interrupt_Hanlder.
  201.    --  Always consider a null handler as registered.
  202.  
  203.    function Is_Registered
  204.      (Handler : Ada.Interrupts.Parameterless_Handler) return boolean;
  205.  
  206.    --  end of local procedure declarations.
  207.  
  208.  
  209.    task body Handler_Manager is
  210.       Default_Action : aliased RTE.struct_sigaction;
  211.       Oact           : aliased RTE.struct_sigaction;
  212.       Result         : Interfaces.C.POSIX_Error.Return_Code;
  213.       Error          : Boolean;
  214.    begin
  215.  
  216.       System.Tasking.Utilities.Make_Independent;
  217.  
  218.       Default_Action.sa_handler := Storage_Elements.To_Address (RTE.SIG_DFL);
  219.  
  220.       Unmask_All_Interrupts;
  221.       --  Initially unmask all interrupts so that the default action
  222.       --  is enforced.
  223.  
  224.       --  Notice : When a task is created it inherits its signal mask from the
  225.       --  calling task and all usable interrupts are masked initially.
  226.       --  (cf: Initialize_LL_Tasks, Create_LL_Task, LL_Wrapper in s-taspri.adb)
  227.  
  228.       loop
  229.  
  230.          select
  231.  
  232.          accept Bind_Handler (Interrupt : Ada.Interrupts.Interrupt_ID) do
  233.  
  234.             --  This entry is called only when the Interrupt is Unblocked on
  235.             --  the process level.
  236.  
  237.             Thread_Block_Interrupt (Interrupt);
  238.             --  Mask this task for the given Interrupt so that all tasks
  239.             --  are masked for the Interrupt and the actuall delivery of the
  240.             --  Interrupt will be caught using "sigwait" by the corresponding
  241.             --  Handler_Task.
  242.  
  243.             Cond_Signal (C (Interrupt));
  244.             --  we have installed a Handler or an Entry before we called
  245.             --  this entry. If the Handler Task is waiting to be awakened,
  246.             --  do it here. Otherwise, the signal will be discarded.
  247.  
  248.          end Bind_Handler;
  249.  
  250.          or accept Unbind_Handler (Interrupt : Ada.Interrupts.Interrupt_ID) do
  251.  
  252.             --  This entry is called only when the Interrupt is Unblocked on
  253.             --  the process level.
  254.  
  255.             --  Currently, there is a Handler or an Entry attached and
  256.             --  corresponding Hanlder_Task is waiting on "sigwait."
  257.  
  258.             Signal_Task (Handler_Task_IDs (Interrupt), Interrupt);
  259.             --  We have to wake the Handler_Task up and make it
  260.             --  wait on condition variable.
  261.  
  262.             RTE.sigaction
  263.               (RTE.Signal (Interrupt),
  264.                Default_Action'Access,
  265.                Oact'Access,
  266.                Result);
  267.             pragma Assert (Result /= Failure or else
  268.               Utilities.Runtime_Assert_Shutdown (
  269.                 "Interrupt Failure---sigaction"));
  270.             --  restore the default action in case it is ruined.
  271.  
  272.             Thread_Unblock_Interrupt (Interrupt);
  273.             --  unmake the Interrupt for this task in order to
  274.             --  allow default action again.
  275.  
  276.          end Unbind_Handler;
  277.  
  278.          or accept Block_Interrupt (Interrupt : Ada.Interrupts.Interrupt_ID) do
  279.  
  280.             --  This entry is called only when the Interrupt is Unblocked on
  281.             --  the process level.
  282.  
  283.             Thread_Block_Interrupt (Interrupt);
  284.             --  Mask this task for the given Interrupt so that all tasks
  285.             --  are masked for the Interrupt.
  286.  
  287.             if User_Installed (Interrupt) then
  288.                --  this is the case where the Handler_Task is waiting on
  289.                --  "sigwait." Wake it up and make it wait on Cond.
  290.                Signal_Task (Handler_Task_IDs (Interrupt), Interrupt);
  291.             end if;
  292.  
  293.          end Block_Interrupt;
  294.  
  295.          or accept
  296.            Unblock_Interrupt (Interrupt : Ada.Interrupts.Interrupt_ID) do
  297.  
  298.             --  This entry is called only when the Interrupt is Blocked on
  299.             --  the process level.
  300.  
  301.             if not User_Installed (Interrupt) then
  302.                --  No handler is attached. Unmask the Interrupt so that
  303.                --  the default action can be carried out.
  304.                Thread_Unblock_Interrupt (Interrupt);
  305.             end if;
  306.  
  307.             Cond_Signal (C (Interrupt));
  308.             --  The Handler Task must be waiting on the Cond variable
  309.             --  since it was being blocked. Wake it up and let it change
  310.             --  it place of waiting according to its new state.
  311.             --  If there is no Handler_Task being activated, this signal
  312.             --  will be lost.
  313.  
  314.          end Unblock_Interrupt;
  315.  
  316.          end select;
  317.  
  318.       end loop;
  319.    end Handler_Manager;
  320.  
  321.    task body Handler_Task is
  322.       Sigwait_Mask   : aliased RTE.Signal_Set;
  323.       Sigwait_Signal : RTE.Signal;
  324.       Result         : Interfaces.C.POSIX_Error.Return_Code;
  325.       Error          : Boolean;
  326.    begin
  327.       System.Tasking.Utilities.Make_Independent;
  328.       --  By making this task independent of master, when the process
  329.       --  goes away, the Handler_Task will terminate gracefully.
  330.  
  331.       Handler_Task_IDs (Interrupt) := System.Tasking.Self;
  332.       --  Save the ID of this task so that others can explicitly
  333.       --  send a signal to this task (thread) using Send_Signal (pthread_kill).
  334.  
  335.       RTE.sigemptyset (Sigwait_Mask'Access, Result);
  336.       pragma Assert (Result /= Failure or else
  337.         Utilities.Runtime_Assert_Shutdown ("Interrupt Failure---sigemptyset"));
  338.       RTE.sigaddset (Sigwait_Mask'Access, RTE.Signal (Interrupt), Result);
  339.       pragma Assert (Result /= Failure or else
  340.         Utilities.Runtime_Assert_Shutdown ("Interrupt Failure---sigaddset"));
  341.  
  342.       loop
  343.          if not User_Installed (Interrupt)
  344.             --  No Interrupt binding. If there is an interrupt,
  345.             --  Handler_Manager will take default action.
  346.  
  347.            or else Status_Blocked (Interrupt) then
  348.             --  Interrupt is blocked.
  349.             --  Stay here, so we won't catch the Interrupt.
  350.  
  351.             Write_Lock  (M (Interrupt), Error);
  352.             Cond_Wait  (C (Interrupt), M (Interrupt));
  353.             Unlock (M (Interrupt));
  354.  
  355.          else
  356.             --  A Handler or an Entry is installed. At this point all tasks
  357.             --  mask for the Interrupt is masked. Catch the Signal using
  358.             --  "sigwait."
  359.  
  360.             Interfaces.C.Pthreads.sigwait
  361.                (Sigwait_Mask, Sigwait_Signal, Result);
  362.             pragma Assert (Result /= Failure or else
  363.               Utilities.Runtime_Assert_Shutdown
  364.                 ("Interrupt Failure---sigwait"));
  365.  
  366.             --  This task may wake up from sigwait by receiving a signal
  367.             --  from the Handler_Manager for unbinding a Interrupt Handler or
  368.             --  an Entry. Or it could be a wake up from status change
  369.             --  (Unblocked -> Blocked). If that is not the case, we should
  370.             --  exceute the attached Procedure or Entry.
  371.  
  372.             if Status_Blocked (Interrupt) then
  373.                null;
  374.             elsif User_Handlers (Interrupt) /= Null_Handler_Assoc then
  375.                User_Handlers (Interrupt).H.all;
  376.             elsif User_Entries (Interrupt) /= Null_Entry_Assoc then
  377.                System.Tasking.Rendezvous.Call_Simple
  378.                  (User_Entries (Interrupt).T, User_Entries (Interrupt).E,
  379.                   System.Null_Address);
  380.             end if;
  381.  
  382.          end if;
  383.       end loop;
  384.    end Handler_Task;
  385.  
  386.    -----------------
  387.    -- Is_Reserved --
  388.    -----------------
  389.  
  390.    function Is_Reserved (Interrupt : Ada.Interrupts.Interrupt_ID)
  391.      return Boolean is
  392.    begin
  393.       return not Usable_Interrupts (Interrupt);
  394.    end Is_Reserved;
  395.  
  396.    -----------------
  397.    -- Is_Attached --
  398.    -----------------
  399.  
  400.    function Is_Attached (Interrupt : Ada.Interrupts.Interrupt_ID)
  401.      return Boolean is
  402.       Test  : Boolean;
  403.       Error : Boolean;
  404.    begin
  405.       if Is_Reserved (Interrupt) then
  406.          raise Program_Error;
  407.       end if;
  408.  
  409.       Write_Lock (M (Interrupt), Error);
  410.       Test := User_Handlers (Interrupt) /= Null_Handler_Assoc;
  411.       Unlock (M (Interrupt));
  412.       return Test;
  413.    end Is_Attached;
  414.  
  415.    ---------------------
  416.    -- Current_Handler --
  417.    ---------------------
  418.  
  419.    function Current_Handler (Interrupt : Ada.Interrupts.Interrupt_ID)
  420.      return Ada.Interrupts.Parameterless_Handler is
  421.  
  422.       Handler : Ada.Interrupts.Parameterless_Handler;
  423.       Error   : Boolean;
  424.    begin
  425.       if Is_Reserved (Interrupt) then
  426.          raise Program_Error;
  427.       end if;
  428.  
  429.       Write_Lock (M (Interrupt), Error);
  430.       Handler := User_Handlers (Interrupt).H;
  431.       Unlock (M (Interrupt));
  432.       return Handler;
  433.    end Current_Handler;
  434.  
  435.    --------------------
  436.    -- Attach_Handler --
  437.    --------------------
  438.  
  439.    --  Calling this procedure with New_Handler = null and Static = true
  440.    --  means that we want to Detach the current handler regardless of
  441.    --  the previous handler's binding status (ie. do not care if
  442.    --  it is a dynamic or static handler).
  443.  
  444.    procedure Attach_Handler
  445.      (New_Handler : in Ada.Interrupts.Parameterless_Handler;
  446.       Interrupt   : in Ada.Interrupts.Interrupt_ID;
  447.       Static      : in boolean := false) is
  448.  
  449.       Old_Handler : Ada.Interrupts.Parameterless_Handler;
  450.       Error       : Boolean;
  451.    begin
  452.       if Is_Reserved (Interrupt) then
  453.          raise Program_Error;
  454.       end if;
  455.  
  456.       Write_Lock (M (Interrupt), Error);
  457.  
  458.       --  In case we have an Interrupt Entry already installed,
  459.       --  raise a program error.
  460.       if User_Entries (Interrupt) /= Null_Entry_Assoc then
  461.          Unlock (M (Interrupt));
  462.          raise Program_Error;
  463.       end if;
  464.  
  465.       if not Static and then
  466.         (User_Handlers (Interrupt).Static or else
  467.          --  tries to overwrite a static Interrupt Handler with a
  468.          --  dynamic Handler
  469.          not Is_Registered (New_Handler)) then
  470.          --  The new handler is not specified as an Interrupt
  471.          --  Handler by a pragma.
  472.  
  473.          Unlock (M (Interrupt));
  474.          raise Program_Error;
  475.       end if;
  476.  
  477.       Unprotected_Exchange_Handler
  478.         (Old_Handler, New_Handler, Interrupt, Static);
  479.       Unlock (M (Interrupt));
  480.    end Attach_Handler;
  481.  
  482.    ----------------------
  483.    -- Exchange_Handler --
  484.    ----------------------
  485.  
  486.    --  Calling this procedure with New_Handler = null and Static = true
  487.    --  means that we want to Detach the current handler regardless of
  488.    --  the previous handler's binding status (ie. do not care if
  489.    --  it is a dynamic or static handler).
  490.  
  491.    procedure Exchange_Handler
  492.      (Old_Handler : out Ada.Interrupts.Parameterless_Handler;
  493.       New_Handler : in Ada.Interrupts.Parameterless_Handler;
  494.       Interrupt   : in Ada.Interrupts.Interrupt_ID;
  495.       Static      : in boolean := false) is
  496.  
  497.       Error : Boolean;
  498.    begin
  499.       if Is_Reserved (Interrupt) then
  500.          raise Program_Error;
  501.       end if;
  502.  
  503.       Write_Lock (M (Interrupt), Error);
  504.  
  505.       --  In case we have an Interrupt Entry already installed,
  506.       --  raise a program error.
  507.       if User_Entries (Interrupt) /= Null_Entry_Assoc then
  508.          Unlock (M (Interrupt));
  509.          raise Program_Error;
  510.       end if;
  511.  
  512.       if not Static and then
  513.         (User_Handlers (Interrupt).Static or else
  514.          --  tries to overwrite a static Interrupt Handler with a
  515.          --  dynamic Handler
  516.          not Is_Registered (New_Handler)) then
  517.          --  The new handler is not specified as an Interrupt
  518.          --  Handler by a pragma.
  519.  
  520.          Unlock (M (Interrupt));
  521.          raise Program_Error;
  522.       end if;
  523.  
  524.       Unprotected_Exchange_Handler
  525.         (Old_Handler, New_Handler, Interrupt, Static);
  526.       Unlock (M (Interrupt));
  527.    end Exchange_Handler;
  528.  
  529.    ----------------------------------
  530.    -- Unprotected_Exchange_Handler --
  531.    ----------------------------------
  532.  
  533.    procedure Unprotected_Exchange_Handler
  534.      (Old_Handler : out Ada.Interrupts.Parameterless_Handler;
  535.       New_Handler : in Ada.Interrupts.Parameterless_Handler;
  536.       Interrupt   : in Ada.Interrupts.Interrupt_ID;
  537.       Static      : in boolean := false) is
  538.    begin
  539.  
  540.       --  Save the old handler
  541.       Old_Handler := User_Handlers (Interrupt).H;
  542.  
  543.       --  The new handler
  544.       User_Handlers (Interrupt).H := New_Handler;
  545.  
  546.       --  Consider null handler dynamic regardless of Static information.
  547.       if New_Handler = null then
  548.          User_Handlers (Interrupt).Static := false;
  549.       else
  550.          User_Handlers (Interrupt).Static := Static;
  551.       end if;
  552.  
  553.       if Handler_Access (Interrupt) = null then
  554.          --  if the Handler_Task is not yet created, do it now.
  555.          Handler_Access (Interrupt) := new Handler_Task (Interrupt);
  556.       end if;
  557.  
  558.       if Status_Blocked (Interrupt) then
  559.          --  if the signal is currently blocked,
  560.          --  no further operations are needed.
  561.          return;
  562.       end if;
  563.  
  564.       if (New_Handler = null) then
  565.          if Old_Handler /= null then
  566.             Handler_Manager.Unbind_Handler (Interrupt);
  567.          end if;
  568.          return;
  569.       end if;
  570.  
  571.       if Old_Handler = null then
  572.          Handler_Manager.Bind_Handler (Interrupt);
  573.       end if;
  574.  
  575.    end Unprotected_Exchange_Handler;
  576.  
  577.    --------------------
  578.    -- Detach_Handler --
  579.    --------------------
  580.  
  581.    --  Calling this procedure with Static = true
  582.    --  means that we want to Detach the current handler regardless of
  583.    --  the previous handler's binding status (ie. do not care if
  584.    --  it is a dynamic or static handler).
  585.  
  586.    procedure Detach_Handler
  587.      (Interrupt : in Ada.Interrupts.Interrupt_ID;
  588.       Static    : in boolean := false) is
  589.       Old_Handler : Ada.Interrupts.Parameterless_Handler;
  590.       Error : Boolean;
  591.    begin
  592.       if Is_Reserved (Interrupt) then
  593.          raise Program_Error;
  594.       end if;
  595.  
  596.       Write_Lock (M (Interrupt), Error);
  597.  
  598.       --  In case we have an Interrupt Entry already installed,
  599.       --  raise a program error.
  600.       if User_Entries (Interrupt) /= Null_Entry_Assoc then
  601.          Unlock (M (Interrupt));
  602.          raise Program_Error;
  603.       end if;
  604.  
  605.       if not Static and then User_Handlers (Interrupt).Static then
  606.          --  tries to detach a static Interrupt Handler.
  607.  
  608.          Unlock (M (Interrupt));
  609.          raise Program_Error;
  610.       end if;
  611.  
  612.       Unprotected_Exchange_Handler (Old_Handler, null, Interrupt);
  613.       Unlock (M (Interrupt));
  614.    end Detach_Handler;
  615.  
  616.    ---------------
  617.    -- Reference --
  618.    ---------------
  619.  
  620.    function Reference (Interrupt : Ada.Interrupts.Interrupt_ID)
  621.      return System.Address is
  622.       Signal : System.Address :=
  623.         System.Storage_Elements.To_Address
  624.           (System.Storage_Elements.Integer_Address (Interrupt));
  625.    begin
  626.       if Is_Reserved (Interrupt) then
  627.       --  Only usable Interrupts can be used for binding it to an Entry.
  628.          raise Program_Error;
  629.       end if;
  630.       return Signal;
  631.    end Reference;
  632.  
  633.    ----------------------------------
  634.    --  Register_Interrupt_Handler  --
  635.    ----------------------------------
  636.  
  637.    procedure Register_Interrupt_Handler
  638.      (Handler : Ada.Interrupts.Parameterless_Handler) is
  639.       New_Node_Ptr : R_Link;
  640.       Ptr  : R_Link;
  641.    begin
  642.       --  This routine registers the Handler as usable for Dynamic
  643.       --  Interrupt Handler. Routines attaching and detaching Handler
  644.       --  dynamically should first consult if the Handler is rgistered.
  645.       --  A Program Error should be raised if it is not registered.
  646.  
  647.       --  The pragma Interrupt_Handler can only appear in the library
  648.       --  level PO definition and instantiation. Therefore, we do not need
  649.       --  to implement Unregistering operation. Neither we need to
  650.       --  protect the queue structure using a Write Lock.
  651.  
  652.       pragma Assert (Handler /= null or else
  653.         Utilities.Runtime_Assert_Shutdown (
  654.           "Interrupt Failure---a null handler should not be registered"));
  655.  
  656.       New_Node_Ptr := new Registered_Handler;
  657.       New_Node_Ptr.H := Handler;
  658.  
  659.       if Registered_Handler_Head = null then
  660.          Registered_Handler_Head := New_Node_Ptr;
  661.          Registered_Handler_Tail := New_Node_Ptr;
  662.       else
  663.          Registered_Handler_Tail.Next := New_Node_Ptr;
  664.          Registered_Handler_Tail := New_Node_Ptr;
  665.       end if;
  666.  
  667.    end Register_Interrupt_Handler;
  668.  
  669.    function Is_Registered
  670.      (Handler : Ada.Interrupts.Parameterless_Handler) return boolean is
  671.       Ptr : R_Link;
  672.    begin
  673.       if Handler = null then
  674.          return true;
  675.       end if;
  676.  
  677.       Ptr := Registered_Handler_Head;
  678.  
  679.       while (Ptr /= null) loop
  680.          if Ptr.H = Handler then
  681.             return true;
  682.          end if;
  683.          Ptr := Ptr.Next;
  684.       end loop;
  685.       return false;
  686.  
  687.    end Is_Registered;
  688.  
  689.    ---------------------------
  690.    -- Unmask_All_Interrupts --
  691.    ---------------------------
  692.  
  693.    --  Unmask all usable interrupts for calling task (thread).
  694.  
  695.    procedure Unmask_All_Interrupts is
  696.       Signal_Mask, Old_Set : aliased RTE.Signal_Set;
  697.       Result : Interfaces.C.POSIX_Error.Return_Code;
  698.    begin
  699.       RTE.sigfillset (Signal_Mask'Access, Result);
  700.       pragma Assert (Result /= Failure or else
  701.         Utilities.Runtime_Assert_Shutdown ("Interrupt Failure---sigfillset"));
  702.  
  703.       RTE.sigprocmask (
  704.         RTE.SIG_UNBLOCK, Signal_Mask'Access, Old_Set'Access, Result);
  705.       pragma Assert (Result /= Failure or else
  706.         Utilities.Runtime_Assert_Shutdown (
  707.           "Interrupt Failure---sigprocmask"));
  708.    end Unmask_All_Interrupts;
  709.  
  710.    ----------------------------
  711.    -- Thread_Block_Interrupt --
  712.    ----------------------------
  713.  
  714.    procedure Thread_Block_Interrupt
  715.      (Interrupt : Ada.Interrupts.Interrupt_ID) is
  716.       Signal_Mask, Old_Set : aliased RTE.Signal_Set;
  717.       Result : Interfaces.C.POSIX_Error.Return_Code;
  718.    begin
  719.       RTE.sigemptyset (Signal_Mask'Access, Result);
  720.       pragma Assert (Result /= Failure or else
  721.         Utilities.Runtime_Assert_Shutdown ("Interrupt Failure---sigemptyset"));
  722.       RTE.sigaddset (Signal_Mask'Access, RTE.Signal (Interrupt), Result);
  723.       pragma Assert (Result /= Failure or else
  724.         Utilities.Runtime_Assert_Shutdown ("Interrupt Failure---sigaddset"));
  725.       RTE.sigprocmask (
  726.         RTE.SIG_BLOCK, Signal_Mask'Access, Old_Set'Access, Result);
  727.       pragma Assert (Result /= Failure or else
  728.         Utilities.Runtime_Assert_Shutdown (
  729.           "Interrupt Failure---sigprocmask"));
  730.    end Thread_Block_Interrupt;
  731.  
  732.    ------------------------------
  733.    -- Thread_Unblock_Interrupt --
  734.    ------------------------------
  735.  
  736.    procedure Thread_Unblock_Interrupt
  737.      (Interrupt : Ada.Interrupts.Interrupt_ID) is
  738.       Signal_Mask, Old_Set : aliased RTE.Signal_Set;
  739.       Result : Interfaces.C.POSIX_Error.Return_Code;
  740.    begin
  741.       RTE.sigemptyset (Signal_Mask'Access, Result);
  742.       pragma Assert (Result /= Failure or else
  743.         Utilities.Runtime_Assert_Shutdown ("Interrupt Failure---sigemptyset"));
  744.       RTE.sigaddset (Signal_Mask'Access, RTE.Signal (Interrupt), Result);
  745.       pragma Assert (Result /= Failure or else
  746.         Utilities.Runtime_Assert_Shutdown ("Interrupt Failure---sigaddset"));
  747.       RTE.sigprocmask (
  748.         RTE.SIG_UNBLOCK, Signal_Mask'Access, Old_Set'Access, Result);
  749.       pragma Assert (Result /= Failure or else
  750.         Utilities.Runtime_Assert_Shutdown (
  751.           "Interrupt Failure---sigprocmask"));
  752.    end Thread_Unblock_Interrupt;
  753.  
  754.    --------------------
  755.    -- User_Installed --
  756.    --------------------
  757.  
  758.    function User_Installed (Interrupt : Ada.Interrupts.Interrupt_ID)
  759.      return Boolean is
  760.    begin
  761.       return
  762.         User_Handlers (Interrupt) /= Null_Handler_Assoc or else
  763.           User_Entries (Interrupt) /= Null_Entry_Assoc;
  764.    end User_Installed;
  765.  
  766.    -------------------
  767.    --  Signal_Task  --
  768.    -------------------
  769.  
  770.    procedure Signal_Task
  771.      (T : System.Tasking.Task_ID;
  772.       Interrupt : Ada.Interrupts.Interrupt_ID) is
  773.  
  774.       type ATCB_Ptr is access Tasking.Ada_Task_Control_Block;
  775.  
  776.       function Task_ID_To_ATCB_Ptr is new
  777.         Unchecked_Conversion (Tasking.Task_ID, ATCB_Ptr);
  778.  
  779.       T_Access : Task_Primitives.TCB_Ptr :=
  780.         Task_ID_To_ATCB_Ptr (T).LL_TCB'Unchecked_Access;
  781.       Result : Interfaces.C.POSIX_Error.Return_Code;
  782.    begin
  783.       Interfaces.C.Pthreads.pthread_kill
  784.          (T_Access.Thread, RTE.Signal (Interrupt), Result);
  785.       pragma Assert (Result /= Failure or else
  786.         Utilities.Runtime_Assert_Shutdown (
  787.           "Interrupt Failure---pthread_kill"));
  788.    end Signal_Task;
  789.  
  790.    -----------------------------
  791.    -- Bind_Interrupt_To_Entry --
  792.    -----------------------------
  793.  
  794.    --  This procedure raises a Program_Error if it tries to
  795.    --  bind an interrupt to which an Interrupt Entry or a Protected
  796.    --  Procedure is already bound.
  797.  
  798.    procedure Bind_Interrupt_To_Entry
  799.      (T       : System.Tasking.Task_ID;
  800.       E       : System.Tasking.Task_Entry_Index;
  801.       Int_Ref : System.Address) is
  802.  
  803.       Interrupt :
  804.         Ada.Interrupts.Interrupt_ID :=
  805.           Ada.Interrupts.Interrupt_ID
  806.             (System.Storage_Elements.To_Integer (Int_Ref));
  807.       Error : Boolean;
  808.    begin
  809.       if Is_Reserved (Interrupt) then
  810.          raise Program_Error;
  811.       end if;
  812.  
  813.       Write_Lock (M (Interrupt), Error);
  814.  
  815.       --  if there is a binding already (either a Procedure or an Entry),
  816.       --  raise Program_Error.
  817.       if User_Installed (Interrupt) then
  818.          Unlock (M (Interrupt));
  819.          raise Program_Error;
  820.       end if;
  821.  
  822.       User_Entries (Interrupt) := Entry_Assoc' (T => T, E => E);
  823.  
  824.       --  Indicate the attachment of Interrupt Entry in ATCB.
  825.       T.Interrupt_Entry := true;
  826.  
  827.       if Handler_Access (Interrupt) = null then
  828.          Handler_Access (Interrupt) := new Handler_Task (Interrupt);
  829.          --  Invoke the corresponding Handler_Task
  830.       end if;
  831.  
  832.       if not Status_Blocked (Interrupt) then
  833.          Handler_Manager.Bind_Handler (Interrupt);
  834.       end if;
  835.  
  836.       Unlock (M (Interrupt));
  837.  
  838.    end Bind_Interrupt_To_Entry;
  839.  
  840.    ------------------------------
  841.    -- Detach_Interrupt_Entries --
  842.    ------------------------------
  843.  
  844.    procedure Detach_Interrupt_Entries (T : Tasking.Task_ID) is
  845.       Error : Boolean;
  846.    begin
  847.       for I in Ada.Interrupts.Interrupt_ID'Range loop
  848.          if not Is_Reserved (I) then
  849.             Write_Lock (M (I), Error);
  850.             if User_Entries (I) /= Null_Entry_Assoc and then
  851.               User_Entries (I).T = T then
  852.                User_Entries (I) := Null_Entry_Assoc;
  853.                if not Status_Blocked (I) then
  854.                   Handler_Manager.Unbind_Handler (I);
  855.                end if;
  856.             end if;
  857.             Unlock (M (I));
  858.          end if;
  859.       end loop;
  860.  
  861.       --  Indicate in ATCB that no Interrupt Entries are attached.
  862.       T.Interrupt_Entry := false;
  863.  
  864.    end Detach_Interrupt_Entries;
  865.  
  866.    ---------------------
  867.    -- Block_Interrupt --
  868.    ---------------------
  869.  
  870.    procedure Block_Interrupt (Interrupt : Ada.Interrupts.Interrupt_ID) is
  871.       Error : Boolean;
  872.    begin
  873.       if Is_Reserved (Interrupt) then
  874.          raise Program_Error;
  875.       end if;
  876.  
  877.       if Is_Blocked (Interrupt) then
  878.          return;
  879.       end if;
  880.  
  881.       Write_Lock (M (Interrupt), Error);
  882.       Status_Blocked (Interrupt) := true;
  883.       Handler_Manager.Block_Interrupt (Interrupt);
  884.       Unlock (M (Interrupt));
  885.  
  886.    end Block_Interrupt;
  887.  
  888.    -----------------------
  889.    -- Unblock_Interrupt --
  890.    -----------------------
  891.  
  892.    procedure Unblock_Interrupt (Interrupt : Ada.Interrupts.Interrupt_ID) is
  893.       Error : Boolean;
  894.    begin
  895.       if Is_Reserved (Interrupt) then
  896.          raise Program_Error;
  897.       end if;
  898.  
  899.       if not Is_Blocked (Interrupt) then
  900.          return;
  901.       end if;
  902.  
  903.       Write_Lock (M (Interrupt), Error);
  904.       Status_Blocked (Interrupt) := false;
  905.       Handler_Manager.Unblock_Interrupt (Interrupt);
  906.       Unlock (M (Interrupt));
  907.  
  908.    end Unblock_Interrupt;
  909.  
  910.    ----------------
  911.    -- Is_Blocked --
  912.    ----------------
  913.  
  914.    function Is_Blocked (Interrupt : Ada.Interrupts.Interrupt_ID)
  915.      return boolean is
  916.       Error : Boolean;
  917.       Tmp   : Boolean;
  918.    begin
  919.       if Is_Reserved (Interrupt) then
  920.          raise Program_Error;
  921.       end if;
  922.  
  923.       Write_Lock (M (Interrupt), Error);
  924.       Tmp := Status_Blocked (Interrupt);
  925.       Unlock (M (Interrupt));
  926.  
  927.       return Tmp;
  928.    end Is_Blocked;
  929.  
  930.    ----------------------------------
  931.    -- Initialize_Usable_Interrupts --
  932.    ----------------------------------
  933.  
  934.  
  935.    --  Only those interrupts classified as Asynchronous Signals in RTE
  936.    --  can be used by users.
  937.  
  938.    procedure Initialize_Usable_Interrupts is
  939.    begin
  940.       Usable_Interrupts :=
  941.         (SIGHUP | SIGQUIT | SIGPIPE | SIGTERM | SIGUSR2  => true,
  942.          others => false);
  943.  
  944.       --  Reflect OS specific Asynchronous signals
  945.       for i in RTE.OS_Specific_Async_Signals'First + 1 ..
  946.         RTE.OS_Specific_Async_Signals'Last loop
  947.          Usable_Interrupts (Ada.Interrupts.Interrupt_ID
  948.            (RTE.OS_Specific_Async_Signals (i))) := true;
  949.       end loop;
  950.    end Initialize_Usable_Interrupts;
  951.  
  952. begin
  953.    Initialize_Usable_Interrupts;
  954. end System.Interrupts;
  955.